package com.bluexmicro.bluetooth.peripheral.handler

import android.annotation.SuppressLint
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import com.bluexmicro.bluetooth.LogUtils
import com.bluexmicro.bluetooth.model.GattStatus
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

typealias ReadCallback = (
    gatt: BluetoothGatt,
    characteristic: BluetoothGattCharacteristic,
    value: ByteArray,
    status: Int
) -> Unit

class ReadHandler {

    private var callback: ReadCallback? = null
    private var cancellableContinuation: CancellableContinuation<Result<ByteArray>>? =
        null

    fun onCharacteristicRead(
        gatt: BluetoothGatt,
        characteristic: BluetoothGattCharacteristic,
        value: ByteArray,
        status: Int
    ) {
        callback?.invoke(gatt, characteristic, value, status)
    }

    private fun setCallback(cb: ReadCallback) {
        this.callback = cb
    }

    fun isActive(): Boolean {
        return cancellableContinuation?.isActive == true
    }

    @SuppressLint("MissingPermission")
    suspend fun execute(
        gatt: BluetoothGatt,
        characteristic: BluetoothGattCharacteristic,
    ) = suspendCancellableCoroutine<Result<ByteArray>> {
        cancellableContinuation = it
        setCallback { _, c, value, status ->
            if (c.uuid.equals(characteristic.uuid)) {
                if (it.isActive) {
                    this.callback = null
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        it.resume(Result.success(value))
                    } else {
                        val reason = GattStatus.fromValue(status).name
                        it.resume(Result.failure(IllegalStateException("Read Failed, gatt errorCode:$status, reason: $reason")))
                    }
                }
            }
        }

        if (it.isActive) {
            if (characteristic.properties and BluetoothGattCharacteristic.PROPERTY_READ != BluetoothGattCharacteristic.PROPERTY_READ) {
                this.callback = null
                val error = "This characteristic not support READ"
                LogUtils.sendLog(
                    mapOf(
                        "mac" to gatt.device.address,
                        "call method" to "readCharacteristic",
                        "service" to characteristic.service.uuid.toString(),
                        "characteristic" to characteristic.uuid.toString(),
                        "detail" to error
                    )
                )
                it.resume(Result.failure(IllegalArgumentException(error)))
            } else {
                val res = gatt.readCharacteristic(characteristic)
                LogUtils.sendLog(
                    mapOf(
                        "mac" to gatt.device.address,
                        "call method" to "readCharacteristic",
                        "service" to characteristic.service.uuid.toString(),
                        "characteristic" to characteristic.uuid.toString(),
                        "detail" to if (res) "done" else "failed"
                    )
                )
                if (!res) {
                    this.callback = null
                    it.resume(Result.failure(IllegalStateException("Read Failed!")))
                }
            }
        }

        it.invokeOnCancellation {
            this.callback = null
        }
    }
}